package com.ror.game;

import com.ror.util.JDialogUtil;

import javax.swing.*;
import javax.swing.border.BevelBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Random;

public class GameJFrame extends JFrame implements KeyListener, ActionListener {
//    private static final String IMAGE_FILE_DIR = "assets/";
    private static final String IMAGE_FILE_DIR = "/Users/ror/Projects/CodeProjects/java-projs/puzzle-game/assets/";
    private static final ArrayList<String> IMAGE_NAMES = new ArrayList<>();
    private static final String IMAGE_FILE_SUFFIX = ".png";
    private static final int[][] IMAGE_INDEX_MATRIX = new int[3][3]; //拼图序号矩阵
    private static final int IMAGE_EDGE = 158; //一块拼图的边长
    private static final int GAP = 5; //通用间距
    private static final ArrayList<JLabel> IMAGE_JLABELS = new ArrayList<>(); //拼图组件列表

    private static Container contentPane; //当前窗口内容面板容器
    private static String curImageName; //当前拼图名称
    private static int stepCount = 0; //已用步数
    private static int missingRow = -1, missingCol = -1; //挖空块的行和列

    private static JFrame gameJFrame; //当前游戏窗口实例
    private static JLabel fullImageLabel; //完整拼图组件
    private static JLabel stepsJLabel; //已用步数界面组件
    private static JMenuItem restartItem; //重开游戏
    private static JMenuItem reLoginItem; //重新登录
    private static JMenuItem closeItem; //关闭游戏
    private static JMenuItem aboutItem; //关于游戏

    private enum STATE {STOPPED, RUNNING, PAUSED}

    private static STATE GAME_STATE = STATE.STOPPED;

    public GameJFrame() {
        gameJFrame = this;

        initJFrame();
        initImages();
        initJMenuBar();

        initImageTable();
        initSteps();
        initHelp();

        this.setVisible(true);
        GAME_STATE = STATE.RUNNING;
    }

    private void initHelp() {
        JLabel helpJLabel = new JLabel("←↑→↓:移动拼图  A(长按):显示原图  R:重开一把  W:直接获胜");
        helpJLabel.setBounds(GAP, IMAGE_EDGE * 3 + GAP * 2 + 20, 400, 20);
        contentPane.add(helpJLabel);
    }

    private void initImages() {
        File assetsDir = new File(IMAGE_FILE_DIR);
        File[] subDirs = assetsDir.listFiles(File::isDirectory);
        if (subDirs == null) return;
        //debug
        boolean hasSteam = false;
        for (File subDir : subDirs) {
            IMAGE_NAMES.add(subDir.getName());
            //debug
            hasSteam = "steam".equals(subDir.getName());
        }
        curImageName = IMAGE_NAMES.get(0);
        //debug
        if (hasSteam) curImageName = "steam";
    }

    private void checkWin() {
        for (int i = 0; i < 9; i++) {
            if (IMAGE_INDEX_MATRIX[i / 3][i % 3] != i) {
                GAME_STATE = STATE.RUNNING;
                return;
            }
        }
        stepsJLabel.setText("You won! 使用步数：" + stepCount);
        GAME_STATE = STATE.STOPPED;
    }

    private void restart() {
        initImageTable();
        updateSteps(0);
        contentPane.repaint();
        GAME_STATE = STATE.RUNNING;
    }

    private void showFullImage() {
        removeImageTable();
        if (fullImageLabel != null) {
            contentPane.remove(fullImageLabel);
        }
        String fullPath = IMAGE_FILE_DIR + curImageName + "/full" + IMAGE_FILE_SUFFIX;
        JLabel fullJLabel = new JLabel(new ImageIcon(fullPath));
        fullJLabel.setBounds(GAP, GAP, IMAGE_EDGE * 3, IMAGE_EDGE * 3);
        fullJLabel.setBorder(new BevelBorder(BevelBorder.LOWERED));
        contentPane.add(fullJLabel);
        fullImageLabel = fullJLabel;
    }

    private void moveImage(int delX, int delY) {
        if (missingRow < 0 || missingCol < 0) return;
        int movingRow = missingRow + delX;
        int movingCol = missingCol + delY;
        if (movingRow < 0 || movingRow > 2 ||
                movingCol < 0 || movingCol > 2) return;
        //互换序号
        int movingIndex = IMAGE_INDEX_MATRIX[movingCol][movingRow];
        IMAGE_INDEX_MATRIX[movingCol][movingRow] = IMAGE_INDEX_MATRIX[missingCol][missingRow];
        IMAGE_INDEX_MATRIX[missingCol][missingRow] = movingIndex;
        //增加步数
        stepCount++;
    }

    private void shuffleIndexMatrix() {
        int[] tempArr = {0, 1, 2, 3, 4, 5, 6, 7, 8};
        //遍历+随机交换法打乱一维数组
        Random r = new Random();
        for (int i = 0; i < tempArr.length; i++) {
            int ri = r.nextInt(tempArr.length);
            int t = tempArr[i];
            tempArr[i] = tempArr[ri];
            tempArr[ri] = t;
        }
        //用乱序一维数组填充矩阵
        for (int i = 0; i < tempArr.length; i++) {
            IMAGE_INDEX_MATRIX[i / 3][i % 3] = tempArr[i];
        }
//        System.out.println(Arrays.deepToString(imgIdxMatrix));
    }

    private void addImage(int x, int y, int idx) {
        String imagePath = IMAGE_FILE_DIR + curImageName + "/" + idx + IMAGE_FILE_SUFFIX;
        ImageIcon icon = new ImageIcon(imagePath);
        //ImageIcon装入JLabel容器
        JLabel jLabel = new JLabel(icon);
        //指定容器位置和大小
        jLabel.setBounds(x, y, IMAGE_EDGE, IMAGE_EDGE);
        //设置容器边框
        jLabel.setBorder(new BevelBorder(BevelBorder.LOWERED));
        //装入内容面板
        contentPane.add(jLabel);
        //装入拼图列表
        IMAGE_JLABELS.add(jLabel);
    }

    private void updateSteps() {
        stepsJLabel.setText("步数：" + stepCount);
    }

    private void updateSteps(int newStepCount) {
        stepCount = newStepCount;
        updateSteps();
    }

    private void initSteps() {
        stepsJLabel = new JLabel("步数：" + stepCount);
        stepsJLabel.setBounds(GAP, IMAGE_EDGE * 3 + GAP * 2, 200, 20);
        contentPane.add(stepsJLabel);
    }

    private void updateImageTable() {
        //清除上一步的拼图
        removeImageTable();
        //加载当前拼图
        for (int i = 0; i < 9; i++) {
            int row = i % 3;
            int col = i / 3;
            int imageIndex = IMAGE_INDEX_MATRIX[col][row];
            //保留最后一块拼图，腾出移动空间
            if (imageIndex == 8) {
                missingRow = row;
                missingCol = col;
                continue;
            }
            addImage(row * IMAGE_EDGE + GAP, col * IMAGE_EDGE + GAP, imageIndex);
        }
    }

    private void removeImageTable() {
        for (JLabel imageJLabel : IMAGE_JLABELS) {
            contentPane.remove(imageJLabel);
        }
    }

    private void initImageTable() {
        //打乱序号矩阵
        shuffleIndexMatrix();
        //更新拼图
        updateImageTable();
    }

    private void initJMenuBar() {
        JMenuBar jMenuBar = new JMenuBar();

        //一级菜单
        JMenu funcJMenu = new JMenu("功能");
        jMenuBar.add(funcJMenu);
        JMenu aboutJMenu = new JMenu("关于");
        jMenuBar.add(aboutJMenu);

        //二级菜单
        JMenu replaceImageJMenu = new JMenu("更换拼图");
        funcJMenu.add(replaceImageJMenu);

        //添加拼图菜单项
        if (IMAGE_NAMES.isEmpty()) {
            replaceImageJMenu.add(new JMenuItem("(暂无拼图)"));
        } else {
            for (String imageName : IMAGE_NAMES) {
                JMenuItem imageItem = new JMenuItem(imageName);
                imageItem.addActionListener(e -> {
                    curImageName = imageName;
                    restart();
                });
                replaceImageJMenu.add(imageItem);
            }
        }

        funcJMenu.add(restartItem = new JMenuItem("重开游戏"));
        funcJMenu.add(reLoginItem = new JMenuItem("重新登录"));
        funcJMenu.add(closeItem = new JMenuItem("关闭游戏"));
        aboutJMenu.add(aboutItem = new JMenuItem("关于游戏"));

        restartItem.addActionListener(this);
        reLoginItem.addActionListener(this);
        closeItem.addActionListener(this);
        aboutItem.addActionListener(this);

        this.setJMenuBar(jMenuBar);
    }

    private void initJFrame() {
        this.setSize(IMAGE_EDGE * 3 + GAP * 2, IMAGE_EDGE * 3 + GAP * 2 + 100);
        this.setTitle("拼图游戏-单机版 v1.0");
        //设置窗口默认居中
        this.setLocationRelativeTo(null);
        //设置关闭模式：EXIT_ON_CLOSE 关闭的同时关闭JVM进程
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        //取消预设布局方式
        this.setLayout(null);
        //设置键盘事件监听
        this.addKeyListener(this);
        contentPane = this.getContentPane();
    }

    @Override
    public void keyTyped(KeyEvent e) {
    }

    @Override
    public void keyPressed(KeyEvent e) {
        if (GAME_STATE != STATE.RUNNING) return;

        if (e.getKeyCode() == 65) { //A
            //显示完整拼图
            showFullImage();
        }
        contentPane.repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {
//        System.out.println(e.getKeyCode());

        switch (e.getKeyCode()) {
            case 82: //R
                //重开游戏
                restart();
                return;
        }

        if (GAME_STATE != STATE.RUNNING) return;

        switch (e.getKeyCode()) {
            case 37: //左
                moveImage(1, 0);
                break;
            case 38: //上
                moveImage(0, 1);
                break;
            case 39: //右
                moveImage(-1, 0);
                break;
            case 40: //下
                moveImage(0, -1);
                break;
            case 65: //A
                //移除正在显示的完整拼图
                contentPane.remove(fullImageLabel);
                break;
            case 87: //W
                //直接胜利
                for (int i = 0; i < 9; i++) {
                    IMAGE_INDEX_MATRIX[i / 3][i % 3] = i;
                }
                break;
        }
        //更新拼图
        updateImageTable();
        //更新步数
        updateSteps();
        //刷新界面
        contentPane.repaint();
        //检查是否胜利
        checkWin();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        Object o = e.getSource();
        if (o == restartItem) {
            restart();
        } else if (o == reLoginItem) {
            LoginJFrame.reLogin();
        } else if (o == closeItem) {
            //直接关闭JVM进程
            System.exit(0);
        } else if (o == aboutItem) {
            JDialogUtil.show("作者：SysTerror"
                    + " 邮箱：sys.terror@outlook.com", 320, 80);
        }
    }
}
